# -*- coding = utf-8 -*-
# @Time : 2024/6/12 9:31
# @Author : 龙王赘婿冷帝彪少
# @File : pc200_power_machine.py
# @Software : PyCharm
# @Description :

# pc200 电源


from socket import *
from threading import Thread
import struct
import time
import binascii
from datetime import datetime, timedelta


class MYTCP:
    current_time = datetime.now()
    last_time = datetime.now()

    TX_HEART = True
    TX_BATTERY = True
    TX_RELAY = True
    TX_RADAR = True

    TX_HEART_FREQUENCY = 1  # Hz
    TX_BATTERY_FREQUENCY = 1  # Hz
    TX_RELAY_FREQUENCY = 5  # Hz
    TX_RADAR_FREQUENCY = 10  # Hz

    def __init__(self):
        # self.ip = "192.168.8.30"
        # self.ip = "192.168.111.250"
        self.ip = "127.0.0.1"
        self.port = 9000
        # self.port = 9001
        # self.port = 9002
        # self.print_recv_data(self.dianyuan_pc_reply(0, 0x30, 0))  # 测试返回原始报文

        self.server_socket = socket(AF_INET, SOCK_STREAM)  # 建立TCP套接字
        self.server_socket.bind((self.ip, self.port))  # 本机监听端口
        self.server_socket.listen(5)
        print("等待接收连接！")
        self.client_socket, self.client_info = self.server_socket.accept()
        print("一个客户端建立连接成功！")
        # self.client_socket = socket(AF_INET, SOCK_STREAM)
        # self.client_socket.connect((self.ip, self.port))
        t1 = Thread(target=self.recv_thread)
        t2 = Thread(target=self.send_thread)
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        self.client_socket.close()

    # 接收线程
    def recv_thread(self):
        while True:
            recv_data = self.client_socket.recv(1024)  # 最大接收1024字节
            self.print_recv_data(recv_data)
            # self.current_time = datetime.now()
            # if self.current_time - self.last_time > timedelta(seconds=1):
            #     print(self.current_time - self.last_time)
            #     print("*"*100)
            # self.last_time = self.current_time
            # self.decode_recv_data(recv_data)

    @staticmethod
    def print_recv_data(raw_data):
        print(f"recv：len = {len(raw_data)} data =", end=" ")
        for i in range(len(raw_data)):
            print(f"{raw_data[i]:02x}", end=" ")
        print()

    def dianyuan_pc_heart(self, time_count):
        protocol_type = 0x20
        data_length = 20

        state = 0
        error1 = 0
        version1 = 1
        version2 = 2
        version3 = 0
        dynamic = 0

        buf = [0xff, 0xfe, protocol_type, data_length, time_count, state, error1, version1, version2, version3, dynamic]
        s = struct.Struct("<2B2HI6B")
        packed_data = s.pack(*buf)
        crc = self.crc16_cal(packed_data)
        crc_pack = struct.Struct('H').pack(crc)
        end = [0xfd, 0xfa]
        end_pack = struct.Struct("2B").pack(*end)
        packed_data = packed_data + crc_pack + end_pack
        return packed_data

    def dianyuan_pc_battery(self, time_count):
        protocol_type = 0x21
        data_length = 40

        charge_id = 1
        charge_flag = 1
        current = 10.1
        voltage = 10.1
        leave_power = 21.1
        sum_power = 30.1
        present = 65.1
        temperature = 18.1

        buf = [0xff, 0xfe, protocol_type, data_length, time_count,
               charge_id, charge_flag, current, voltage,
               leave_power, sum_power, present, temperature
               ]
        s = struct.Struct("<2B2HI2B6f")
        packed_data = s.pack(*buf)
        crc = self.crc16_cal(packed_data)
        crc_pack = struct.Struct('H').pack(crc)
        end = [0xfd, 0xfa]
        end_pack = struct.Struct("2B").pack(*end)
        packed_data = packed_data + crc_pack + end_pack
        return packed_data

    def dianyuan_pc_relay(self, time_count):
        protocol_type = 0x22
        data_length = 22

        switch_flag = 0b00000000000000000001010101010101
        switch_effective = 0b0

        buf = [0xff, 0xfe, protocol_type, data_length, time_count,
               switch_flag,
               switch_effective,
               ]
        s = struct.Struct("<2B2HI2I")
        packed_data = s.pack(*buf)
        crc = self.crc16_cal(packed_data)
        crc_pack = struct.Struct('H').pack(crc)
        end = [0xfd, 0xfa]
        end_pack = struct.Struct("2B").pack(*end)
        packed_data = packed_data + crc_pack + end_pack
        return packed_data

    def dianyuan_pc_radar(self, time_count):
        protocol_type = 0x24
        data_length = 84

        radar_id = 2
        point_number = 4
        p1_id = 1
        p1_long = 13.2
        p1_lat = 25.3
        p1_vlong = 4.2
        p1_vlat = 6.7

        p2_id = 3
        p2_long = 62.2
        p2_lat = 73.3
        p2_vlong = 25.2
        p2_vlat = 82.7

        p3_id = 5
        p3_long = 62.2
        p3_lat = 82.3
        p3_vlong = 62.2
        p3_vlat = 37.7

        p4_id = 7
        p4_long = 48.2
        p4_lat = 62.3
        p4_vlong = 25.2
        p4_vlat = 93.7

        buf = [0xff, 0xfe, protocol_type, data_length, time_count,
               radar_id,
               point_number,
               p1_id,
               p1_long,
               p1_lat,
               p1_vlong,
               p1_vlat,
               p2_id,
               p2_long,
               p2_lat,
               p2_vlong,
               p2_vlat,
               p3_id,
               p3_long,
               p3_lat,
               p3_vlong,
               p3_vlat,
               p4_id,
               p4_long,
               p4_lat,
               p4_vlong,
               p4_vlat,
               ]
        s = struct.Struct("<2B2HI3B4fB4fB4fB4f")
        packed_data = s.pack(*buf)
        crc = self.crc16_cal(packed_data)
        crc_pack = struct.Struct('H').pack(crc)
        end = [0xfd, 0xfa]
        end_pack = struct.Struct("2B").pack(*end)
        packed_data = packed_data + crc_pack + end_pack
        return packed_data

    def dianyuan_pc_reply(self, time_count, typ, tim):
        protocol_type = 0x23
        data_length = 21

        res = 0

        buf = [0xff, 0xfe, protocol_type, data_length, time_count, res, typ, tim]
        s = struct.Struct("<2B2HIBHI")
        packed_data = s.pack(*buf)
        crc = self.crc16_cal(packed_data)
        crc_pack = struct.Struct('H').pack(crc)
        end = [0xfd, 0xfa]
        end_pack = struct.Struct("2B").pack(*end)
        packed_data = packed_data + crc_pack + end_pack
        return packed_data

    @staticmethod
    def crc16_cal(datalist):
        # from "https://code84.com/461550.html"
        test_crc = 0xFFFF
        poly = 0xa001
        # poly=0x8005
        numl = len(datalist)
        for num in range(numl):
            data = datalist[num]
            test_crc = (data & 0xFF) ^ test_crc
            for bit in range(8):
                if (test_crc & 0x1) != 0:
                    test_crc >>= 1
                    test_crc ^= poly
                else:
                    test_crc >>= 1
        return test_crc

    # 发送线程
    def send_thread(self):
        time_count = 0

        heart_tick = datetime.now()
        battery_tick = datetime.now()
        relay_tick = datetime.now()
        radar_tick = datetime.now()

        while True:
            # 给服务端发消息
            # send_data = self.ackermann()
            # self.client_socket.send(send_data)
            # n2 = binascii.b2a_hex(send_data)
            # print(f"n2={n2},type={type(n2)}")

            self.current_time = datetime.now()

            if self.current_time - heart_tick > timedelta(milliseconds=1000 / self.TX_HEART_FREQUENCY) and self.TX_HEART:
                time_count = time_count + 1
                self.client_socket.send(self.dianyuan_pc_heart(time_count))
                heart_tick = self.current_time

            if self.current_time - battery_tick > timedelta(milliseconds=1000 / self.TX_BATTERY_FREQUENCY) and self.TX_BATTERY:
                time_count = time_count + 1
                self.client_socket.send(self.dianyuan_pc_battery(time_count))
                battery_tick = self.current_time

            if self.current_time - relay_tick > timedelta(milliseconds=1000 / self.TX_RELAY_FREQUENCY) and self.TX_RELAY:
                time_count = time_count + 1
                self.client_socket.send(self.dianyuan_pc_relay(time_count))
                relay_tick = self.current_time

            if self.current_time - radar_tick > timedelta(milliseconds=1000 / self.TX_RADAR_FREQUENCY) and self.TX_RADAR:
                time_count = time_count + 1
                self.client_socket.send(self.dianyuan_pc_radar(time_count))
                radar_tick = self.current_time


if __name__ == "__main__":
    obj = MYTCP()